#ifndef RINGBUFFERBYTES_H
#define RINGBUFFERBYTES_H
#include <stdint.h>
#include <mutex>

/**
 *
 *------------------------------------------------------------------------
 * eg.1 有1个数据
 * 0 1 2                    pM=Max-1=m_mask
 * [*|_|_|_|_|______________|_]Max
 * R W
 *
 *
 * eg.2 W=R, 空情况
 * 0 1 2                    pM=Max-1=m_mask
 * [_|_|_|_|_|______________|_]Max
 *   R
 *   W
 *
 *
 * eg.3 W+1=R, 满情况(为区分空情况，最满状态，需要空余一个单位(字节)
 * 0 1 2                 pM=Max-1=m_mask
 * [*|*|*****|_|*|*****|*|*]Max
 *           W R
 *
 *
 * eg.3.1 (W+1)%M=R, 满情况(为区分空情况，最满状态，需要空余一个单位(字节))
 * 0 1 2                 pM=Max-1=m_mask
 * [*|*|*****|*|*|*****|*|_]Max
 * R                     W
 *
 *
 *
 * eg.4 W>R的情况
 * 0 1                         pM=Max-1=m_mask
 * [_|_|_|*|*|*****|*|*|_|_|_|_|_]Max
 *       R             W
 *
 * eg.5 W<R的情况
 * 0 1 2                     pM=Max-1=m_mask
 * [*|*|*|*|*|_|_____|_|*|*|*|*]Max
 *           W         R
 *------------------------------------------------------------------------
 *
 *剩余空间：
 *1) R=W, L=M
 *2) R>W, L=R-W
 *3) R<W, L=R-W+M
 *综合3种情况：
 *        L=(R-W+M)%M
 *考滤满情况，必需要空余一个存储单位(Byte):
 *        L=(R-W+M-1)%M
 *
 * ----------
 *
 * 缓存区中数据大小：N
 *  L + N = M-1
 *  N = M-1 - L
 *  N = M-1 - (R-W+M-1)%M
 *  N = M-1 - (R-W+M-1)%M
 *----------------------------------------------------------------------------
 *
 *取余操作“%”，简化流程
 * M = m_maxSize
 * X % M = X & m_mask;
 *
 **/

/**
 * @brief The RingBuffer class
 * 如需扩展请注意此类中的私有变量及size是否会有可能导致越界(int32_t最多理论支持1G"RingBuffer"内存空间,否则使用int64_t)
 */
typedef struct test_type{
    const char *name;
}test_t;
class RingBuffer
{

public:
    RingBuffer();
    ~RingBuffer();

    /**
     * @brief clear清空缓冲区
     */
    void clear();

    /**
     * @brief setBufferSizePower 设置2的"size"次幂（即2^size）大小的缓存
     * @param size
     * eg. 2^16=64K; 2^17=128K; 2^20=1M; 2^26=64M
     * @param unit_size
     *          单个存储单元的大小, 如是字节:1, 指针:sizeof(void*), 其它:sizeof(uint_type)
     * @return 0：内存分配成功；
     *         <0:内存分配失败；
     * @note:  限制最大可分配内存64M, 即size的最大可用值为26. 太大的缓存空间可能会导致分配失败
     */
    int setBufferSizePower(uint8_t size, uint32_t unit_size);

    /**
     * @brief getBufferSize 获取缓冲区大小
     * @return
     */
    int getBufferSize();

    /**
     * @brief 获取缓冲区中的可用数据大小
     * @return
     */
    uint32_t getDataSize();

    /**
     * @brief freeSize 获取缓冲区中空闲空间大小
     * @return
     */
    uint32_t getFreeSize();

    /**
     * @brief read 非阻塞读取, 为了一次性成功读取所需数据，读取前可使用getDataSize()
     *        确定是否有足够的数据
     * @param buffer 存放位置
     * @param length 预读取长度
     * @return >=0, 实际读取长度
     */
    int read(void *buffer, uint32_t length);
    int readOne(void *one);

    /**
     * @brief writePtr 非阻塞写入, 为了一次性成功写入所有数据，读取前可使用getFreeSize()
     *        确定是否有足够的空闲空间
     * @param buffer 待写入数据
     * @param length 待写入长度
     * @return >=0, 实际写入长度
     */
    int write(void *buffer, uint32_t length);
    int writeOne(void *one);

    void printBytes(uint32_t start, uint32_t length, uint32_t lineLength=0);
    void printBytesHex(uint32_t start, uint32_t length, uint32_t lineLength=0);
    void printTestPtr(int length, test_t* *test=0);
    void printTestStruct(int length, test_t *test=0);
    static void testByte();
    static void testPtr();
    static void testStruct();

private://辅助计算
    uint8_t m_size;//(2^m_size = m_maxSize)
    uint32_t m_mask;//掩码 = m_maxSize - 1//形如0xfff

private:
    uint32_t    m_maxSize;//形如0x1000, 表示buffer中有多少个存储单元
    uint32_t    m_unit_size;//单个存储单元的大小, Byte=sizeof(uint8_t)=1 Ptr=sizeof(void*) = 4 or 8
    void        *m_buffer;//

    int32_t m_pr;//读指针//read  position
    int32_t m_pw;//写指针//write position
    std::mutex m_mutex;//互斥访问缓冲区,保护读写指针
};

#endif // RINGBUFFERBYTES_H